#pragma once
#include<signal.h>
#include"../Acceptor/Acceptor.hpp"
#include"../Channel/Channel.hpp"
#include"../Connection/Connection.hpp"
#include"../LoopThread/LoopThread.hpp"
#include"../Socket/Socket.hpp"

//功能：
//1.Acceptor进行监听套接字管理，绑定主线程baseloop，设置读回调
//2.对新的连接进行管理，设置回调
//3.开启服务器1
class TcpServer{
private:
    uint64_t _id;//自动增长的连接id
    EventLoop _baseloop;//主线程
    Acceptor _acceptor;//监听套接字管理s
    LoopThreadPool _pool;//管理新连接的线程池
    std::unordered_map<uint64_t, ConnectPtr> _conns;//保存管理所有连接对应的shared_ptr对象
    bool _inactive_release;//是否开启非活跃自动销毁，默认为false
    int _timeout;//设置自动销毁的非活跃时间

    using ConnectedCallback = std::function<void(const ConnectPtr&)>;
    using MessageCallback = std::function<void(const ConnectPtr&, Buffer*)>;
    using CloseCallback = std::function<void(const ConnectPtr&)>;
    using AnyEventCallback = std::function<void (const ConnectPtr &)>;
    //新连接的事件回调函数
    ConnectedCallback _connected_callback = nullptr;//连接后的回调
    MessageCallback _message_callback = nullptr;//收到数据后的业务处理回调
    CloseCallback _close_callback = nullptr;//关闭连接的回调
    AnyEventCallback _event_callback = nullptr;//任意事件的回调

private:
    //从服务器中删除连接的回调函数
    //_conns存储了Connection的共享指针，如果服务器不删除，Connection永远不会被删除，这个函数的作用就是删除_conns的一项数据
    //对容器的数据操作要考虑线程安全问题，所以要放到任务池中
    void ServerRemove(const ConnectPtr& conn)
    {
        int id = conn->GetConnfd();
        auto it = _conns.find(id);
        if(it != _conns.end())
        {
            _conns.erase(it);
        }
    }
    void ServerRemovecbInLoop(const ConnectPtr& conn)
    {
        return _baseloop.RunInLoop(std::bind(&TcpServer::ServerRemove, this, conn));
    }

    //监听套接字建立新Connection的读回调函数
    void Connectioncb(int newfd)
    {
        ConnectPtr conn(new Connection(_pool.NextLoop(), _id, newfd));
        //设置conn的事件回调
        if(_close_callback) conn->SetCloseCallback(std::bind(_close_callback, std::placeholders::_1));
        if(_message_callback) conn->SetMessageCallback(std::bind(_message_callback, std::placeholders::_1, std::placeholders::_2));
        if(_connected_callback) conn->SetConnectedCallback(std::bind(_connected_callback, std::placeholders::_1));
        if(_event_callback) conn->SetEventCallback(std::bind(_event_callback, std::placeholders::_1));
        //设置服务器的删除回调
        conn->SetSrvCloseCallback(std::bind(&TcpServer::ServerRemovecbInLoop, this, std::placeholders::_1));
        //设置超时销毁
        if(_inactive_release == true) conn->EnableInactiveReleaseInLoop(_timeout);
        conn->EstablishedInLoop();                                                                          
        _conns.insert(std::make_pair(_id, conn));
        _id++;
    }

    void RunAfter(const task_cb& cb, int delay)
    {
        _baseloop.AddTimer(_id, delay, cb);
        _id++;
    }
public:
    TcpServer(uint16_t port)
    :_acceptor(&_baseloop,port)
    ,_pool(&_baseloop)
    ,_inactive_release(false)
    ,_id(0)
    {
        _acceptor.SetConnectionCallback(std::bind(&TcpServer::Connectioncb, this, std::placeholders::_1));
        _acceptor.Listen();
    }

    //设置Connection的回调
    void SetConnectedCallback(const ConnectedCallback&cb) { _connected_callback = cb; }
    void SetMessageCallback(const MessageCallback&cb) { _message_callback = cb; }
    void SetCloseCallback(const CloseCallback&cb) { _close_callback = cb; }
    void SetEventCallback(const AnyEventCallback&cb) { _event_callback = cb; }

    //设置从属线程的数量
    void SetThreadCount(int count)
    {
        _pool.SetThreadCount(count);
    }

    //设置开启非活跃定时销毁
    void SetInactiveRelease(int timeout)
    {
        _timeout = timeout;
        _inactive_release = true;
    }

    //添加定时任务
    void RunAfterInLoop(const task_cb& cb, int delay)
    {
        _baseloop.RunInLoop(std::bind(&TcpServer::RunAfter, this, cb, delay));
    }

    //启动服务器
    void Start()
    {
        _pool.InitPool();
        _baseloop.Handle();
    }

};

//忽略SIGPIPE信号
//如果客户端关闭，服务器还在send，就会收到这个信号，导致服务器关闭
class NetWork {
    public:
        NetWork() {
            signal(SIGPIPE, SIG_IGN);
        }
};
static NetWork nw;